﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Net.Sockets;
using System.Net;
using System.Runtime.Serialization.Formatters.Binary;
using System.IO;

namespace Mengsk.ERP.Broadcast
{
    public class MessageCenter
    {
        /// <summary>
        /// 唯一实例，类加载器保证生成唯一的
        /// </summary>
        private static readonly MessageCenter instance = new MessageCenter();

        public static MessageCenter Instance { get { return instance; } }

        /// <summary>
        /// 通信的通信的udp商品
        /// </summary>
        private Socket udpSocket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);

        /// <summary>
        /// 获取远程IP，商品的参数
        /// </summary>
        private EndPoint remoteIP = new IPEndPoint(IPAddress.Any, 3666);

        /// <summary>
        /// 接收数据的本地商品
        /// </summary>
        private EndPoint listenSocket = new IPEndPoint(IPAddress.Any, 3666);

        /// <summary>
        /// 需要组播的网段，一台电脑可能有多块网卡，
        /// </summary>
        private EndPoint[] broadcastEndPoint = null;

        private byte[] reciveBuf = new byte[1024 * 1024];

        private byte[] sendBuf = new byte[1024 * 1024];

        private BinaryFormatter binaryFormatter = new BinaryFormatter();

        public event EventHandler<MessageArrviedEventArgs> MessageArrived;

        public MessageCenter()
        {
            //绑定通信商品
            this.udpSocket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.Broadcast, 1);
            this.udpSocket.Bind(listenSocket);
            //获取本地所有网络接口，并生成组播地址
            this.broadcastEndPoint = Dns.GetHostAddresses(Dns.GetHostName()).Where(ip => ip.AddressFamily == AddressFamily.InterNetwork).Select(
                ipa => new IPEndPoint(IPAddress.Parse(ipa.ToString().Substring(0, ipa.ToString().LastIndexOf('.')) + ".255"), 3666)).ToArray();
        }

        /// <summary>
        /// udp收到数据的回调
        /// </summary>
        /// <param name="ar"></param>
        private void DataReciveCallback(IAsyncResult ar)
        {
            try
            {
                int ret = this.udpSocket.EndReceiveFrom(ar, ref this.remoteIP);
                if (ret <= 0)
                {
                    return;
                }
                MemoryStream ms = new MemoryStream(this.reciveBuf, 0, ret);
                Message m = this.binaryFormatter.Deserialize(ms) as Message;
                if (this.MessageArrived != null)
                {
                    this.MessageArrived(this, new MessageArrviedEventArgs(m));
                }
                //开始新的接收
                this.udpSocket.BeginReceiveFrom(this.reciveBuf, 0, this.reciveBuf.Length, SocketFlags.None, ref this.remoteIP, this.DataReciveCallback, null);
            }
            catch
            {
                this.udpSocket.Close();
            }
        }

        /// <summary>
        /// 开始接收数据
        /// </summary>
        public void Start()
        {
            this.udpSocket.BeginReceiveFrom(this.reciveBuf, 0, this.reciveBuf.Length, SocketFlags.None, ref this.remoteIP, this.DataReciveCallback, null);
        }

        /// <summary>
        /// 停止接收数据
        /// </summary>
        public void Stop()
        {
            this.udpSocket.Close();
        }

        /// <summary>
        /// 发送消息
        /// </summary>
        /// <param name="message"></param>
        public void SendMessage(Message message)
        {
            //序列化数据
            MemoryStream ms = new MemoryStream(this.sendBuf);
            this.binaryFormatter.Serialize(ms, message);
            var buf = ms.ToArray();

            //向计算中的每一个网络接口广播数据
            foreach (EndPoint ep in this.broadcastEndPoint)
            {
                this.udpSocket.SendTo(buf, (int)ms.Position, SocketFlags.None, ep);
            }
        }
    }
}
